package com.kubepartners.impactmodel.translator;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import com.kubepartners.impactmodel.model.Graph;
import com.kubepartners.impactmodel.translator.graphml.GraphmlDomWriter;
import com.kubepartners.impactmodel.translator.graphml.GraphmlReader;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;
import com.sleepycat.dbxml.XmlContainer;
import com.sleepycat.dbxml.XmlDocument;
import com.sleepycat.dbxml.XmlException;
import com.sleepycat.dbxml.XmlInputStream;
import com.sleepycat.dbxml.XmlManager;
import com.sleepycat.dbxml.XmlQueryContext;
import com.sleepycat.dbxml.XmlQueryExpression;
import com.sleepycat.dbxml.XmlResults;
import com.sleepycat.dbxml.XmlUpdateContext;
import com.sleepycat.dbxml.XmlValue;

public class GraphDBManager {
	private static Environment environment = null;
	private static XmlManager manager = null;
	
	public static Graph read(String name) {
		GraphReader gr = new GraphmlReader();
		try {
			XmlContainer myContainer = getManager().openContainer("graphs.bdbxml");
			XmlDocument doc = myContainer.getDocument(name);
			parse(doc.getContentAsInputStream(), gr);
		} catch (XmlException e) {
			throw new RuntimeException(e);
		}
        return gr.readGraph(null);
	}
	
    public static void write(Graph g, String name) {
    	GraphmlDomWriter gw = new GraphmlDomWriter();	
    	ByteArrayOutputStream os = new ByteArrayOutputStream();
    	gw.write(g, os);
    	ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());  	
		XmlContainer myContainer;
		try {
			myContainer = getManager().openContainer("graphs.bdbxml");
			XmlUpdateContext theContext = getManager().createUpdateContext();
			XmlInputStream theStream = getManager().createInputStream(is);
			myContainer.putDocument(name, theStream, theContext, null);
		} catch (XmlException e) {
			throw new RuntimeException(e);
		}
    }
    
    private static void parse(InputStream is, GraphReader gr) {
		SAXParserFactory spf = SAXParserFactory.newInstance();
        spf.setNamespaceAware(true);

		// Create a JAXP SAXParser
        SAXParser saxParser;
		try {
			saxParser = spf.newSAXParser();
			 // Get the encapsulated SAX XMLReader
	        XMLReader xmlReader = saxParser.getXMLReader();
	        // Set the ContentHandler of the XMLReader
	        xmlReader.setContentHandler((ContentHandler) gr);
	        // Set an ErrorHandler before parsing
	        xmlReader.setErrorHandler(new DefaultErrorHandler());
	        // Tell the XMLReader to parse the XML document
	        xmlReader.parse(new InputSource(is));       
		} catch (ParserConfigurationException e) {
			throw new RuntimeException(e);
		} catch (SAXException e) {
			throw new RuntimeException(e);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
    
    private static XmlManager getManager() {
    	if (manager == null) {
    		try {
				manager = new XmlManager();
			} catch (XmlException e) {
				throw new RuntimeException(e);
			} catch (FileNotFoundException e) {
				throw new RuntimeException(e);
			}
    	}
    	return manager;
    }
    
    private static Environment getEnvironment() {
    	if (environment == null) {
    		try {
    			File envHome = new File("xmldb/environment");
    			EnvironmentConfig envConf = new EnvironmentConfig();
    		    envConf.setAllowCreate(true);
    		    envConf.setInitializeCache(true);
    		    envConf.setInitializeLocking(true);
    		    envConf.setInitializeLogging(true);
    		    envConf.setTransactional(true);
    		    environment = new Environment(envHome, envConf);
			} catch (XmlException e) {
				throw new RuntimeException(e);
			} catch (FileNotFoundException e) {
				throw new RuntimeException(e);
			} catch (DatabaseException e) {
				throw new RuntimeException(e);
			}
    	}
    	return environment;
    }

}
